package com.glsc.ngateway.platform.service.other;

import cn.hutool.core.util.StrUtil;
import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.ItNetworkDevice;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.ItServerDevice;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.ItVirtualDevice;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.Tag;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.TagProdRel;
import com.glsc.ngateway.common.api.platform.dto.other.TagProdRelDto;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.TagProdRefRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.TagRepository;
import com.glsc.ngateway.common.api.common.ex.GatewayException;
import com.glsc.ngateway.common.api.common.utils.PageUtil;
import com.glsc.ngateway.platform.service.it.NetworkService;
import com.glsc.ngateway.platform.service.it.ServerService;
import com.glsc.ngateway.platform.service.it.VirtualService;
import com.glsc.ngateway.platform.utils.SpecificationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * @Author: libj
 * @Date: 2021/2/2
 * @Desc: 标签信息表
 */
@Service
public class TagService {
    private static Logger logger = LoggerFactory.getLogger(TagService.class);

    @Resource
    private TagRepository tagRepository;
    @Resource
    private TagProdRefRepository tagProdRefRepository;
    @PersistenceContext
    private EntityManager em;
    @Resource
    @Qualifier("namedParameterJdbcTemplate")
    private NamedParameterJdbcTemplate namedParameterJdbcTemplateMysql;

    @Resource
    private NetworkService networkService;
    @Resource
    private ServerService serverService;
    @Resource
    private VirtualService virtualService;

    /**
     * 创建或修改实体
     *
     * @param tag
     */
    public Tag saveTag(Tag tag) {
        //检查必要元素
        if(StrUtil.isEmpty(tag.getTagCode())){
            throw GatewayException.error("标签编码不能为空");
        }

        //标签编码唯一校验
        List<Tag> existTagList = tagRepository.findAllByTagCodeAndTagDeleted(tag.getTagCode(), DictConstant.NO);
        if (!CollectionUtils.isEmpty(existTagList)
                && 1 == existTagList.size()
                && !existTagList.get(0).getTagId().equals(tag.getTagId())) {
            throw GatewayException.error("标签信息标签名称为" + tag.getTagName() + ",标签编码为" + tag.getTagCode() + "的数据已存在");
        }

        return tagRepository.saveAndFlush(tag);
    }

    /**
     * 根据ID查询
     *
     * @return
     */
    public Tag findById(Integer id) {
        Optional<Tag> optional = tagRepository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        } else {
            return null;
        }
    }

    /**
     * 根据prodId查询
     *
     * @return
     */
    public List<TagProdRelDto> findByProdId(Integer prodId) {
//        QTagProdRel qTagProdRel = QTagProdRel.tagProdRel;
//        QTag qTag = QTag.tag;
//        BooleanBuilder where = new BooleanBuilder();
//        if (prodId != null) {
//            where = where.and(qTagProdRel.prodId.eq(prodId));
//        }
//        JPAQueryFactory queryFactory = new JPAQueryFactory(em);
//        JPAQuery<TagProdRelDto> query = queryFactory
//                .select(Projections.bean(
//                        TagProdRelDto.class,//返回自定义实体的类型
//                        qTagProdRel.tagId,
//                        qTag.tagName,
//                        qTagProdRel.prodId
//                        ))
//                .from(qTagProdRel)
//                .where(where).leftJoin(qTag)
//                .on(qTagProdRel.tagId.eq(qTag.tagId));
//        return query.fetch();
        return null;
    }

    /**
     * 分页条件查询
     *
     * @param pageNo
     * @param pageSize
     * @param param
     * @return
     */
    public Page<Tag> findPage(int pageNo, int pageSize, Map<String, Object> param) {
        Sort.Direction direction = Sort.Direction.DESC;
        String sort = "tagId";

        pageNo = PageUtil.initPageNo(pageNo);
        pageSize = PageUtil.initPageSize(pageSize);

        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, direction, sort);
        return tagRepository.findAll(SpecificationUtil.buildSpecification(param, Tag.class), pageable);
    }

    public List<TagProdRelDto> getSelectedProductList(Integer id){
//        QTagProdRel qTagProdRel = QTagProdRel.tagProdRel;
//        QProduct qProduct = QProduct.product;
//        BooleanBuilder where = new BooleanBuilder();
//        where = where.and(qTagProdRel.tagId.eq(id));
//        JPAQueryFactory queryFactory = new JPAQueryFactory(em);
//        JPAQuery<TagProdRelDto> query = queryFactory
//                .select(Projections.bean(
//                        TagProdRelDto.class,//返回自定义实体的类型
//                        qTagProdRel.tagId,
//                        qTagProdRel.prodId,
//                        qProduct.prodName
//                ))
//                .from(qTagProdRel)
//                .where(where).leftJoin(qProduct)
//                .on(qTagProdRel.prodId.eq(qProduct.prodId));
//        return query.fetch();
        return null;
    }

    /**
     * 删除分配产品标签
     *
     * @param tagId
     */
    public void deleteTagProdRefByTagId(Integer tagId) {
        tagProdRefRepository.deleteByTagId(tagId);
    }

    /**
     * 保存分配产品标签
     *
     * @param refs
     */
    public void saveAllRef4Tag(List<TagProdRel> refs) {
        tagProdRefRepository.saveAll(refs);
    }

    /**
     * 刷新自动分配产品标签信息
     *
     * @param tagId
     */
    public void refresh(Integer tagId) {
        Tag tag = this.findById(tagId);
        if (null == tag) {
            throw GatewayException.error("获取标签信息失败,不能进行刷新");
        }
        if(!DictConstant.TAG_SELECT_PROD_METHOD_AUTO.equals(tag.getSelectProdMethod())){
            throw GatewayException.error("产品配置方式为空或者值不为自动配置,不能进行刷新");
        }
        if(null == tag.getSelectProdSql() || "".equals(tag.getSelectProdSql())){
            throw GatewayException.error("产品配置方式为自动配置并且SQL为空,不能进行刷新");
        }
        String sql = tag.getSelectProdSql();
        Map<String, Object> arg = new HashMap<>();
        List<Integer> prodIds = new ArrayList<>();
        try {
            logger.info("刷新自动分配产品标签信息 tagId:" + tagId +",过滤前sql语句：" + sql);
            //sql = StringFilter(sql);
            logger.info("刷新自动分配产品标签信息 tagId:" + tagId +",过滤后sql语句：" + sql);
            prodIds = namedParameterJdbcTemplateMysql.queryForList(sql, arg, Integer.class);
        }catch (Exception e){
            throw GatewayException.error("自动配置SQL查询产品Ids失败,不能进行刷新");
        }
        List<TagProdRel> refs = new ArrayList<>();
        for(Integer prodId:prodIds) {
            TagProdRel ref = new TagProdRel();
            ref.setTagId(tagId);
            ref.setProdId(prodId);
            refs.add(ref);
        }
        this.deleteTagProdRefByTagId(tagId);
        this.saveAllRef4Tag(refs);
    }

    // 过滤特殊字符
    private static String StringFilter(String str) throws PatternSyntaxException {
        // 只允许字母和数字 // String regEx = "[^a-zA-Z0-9]";
        // 清除掉所有特殊字符
        String regEx = regEx = "[`~!@#$%^&*+|{}:;,\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("").trim();
    }

    public Map searchAll(String key) {
        List<ItNetworkDevice> resultNet = networkService.searchNetworkSpecial(key,true);
        List<ItServerDevice> resultServer  = serverService.searchDevice(key,true);
        List<ItVirtualDevice> resultVirtual = virtualService.searchVirtualDevice(key,true);
        Map<String,List<?>> result = new HashMap();
        result.put("networkDevice",resultNet);
        result.put("serverDevice",resultServer);
        result.put("virtualDevice",resultVirtual);
        return result;
    }
}
